Developer Documentation

QuickTime 4 API Documentation

Inside Macintosh: Memory

Previous | Chapter Top | Chapter Contents | Next |

Setting Up the Application Heap

When the Process Manager launches your application, it calls the Memory Manager to create and initialize a memory partition for your application. The Process Manager then loads code segments into memory and sets up the stack, heap, and A5 world (including the jump table) for your application.

To help prevent heap fragmentation, you should also perform some setup of your own early in your application's execution. Depending on the needs of your application, you might want to

The following sections describe in detail how and when to perform these operations.

Changing the Size of the Stack

Most applications allocate space on their stack in a predictable way and do not need to monitor stack space during their execution. For these applications, stack usage usually reaches a maximum in some heavily nested routine. If the stack in your application can never grow beyond a certain size, then to avoid collisions between your stack and heap you simply need to ensure that your stack is large enough to accommodate that size. If you never encounter system error 28 (generated by the stack sniffer when it detects a collision between the stack and the heap) during application testing, then you probably do not need to increase the size of your stack.

Some applications, however, rely heavily on recursive programming techniques, in which one routine repeatedly calls itself or a small group of routines repeatedly call each other. In these applications, even routines with just a few local variables can cause stack overflow, because each time a routine calls itself, a new copy of that routine's parameters and variables is appended to the stack. The problem can become particularly acute if one or more of the local variables is a string, which can require up to 256 bytes of stack space.

You can help prevent your application from crashing because of insufficient stack space by expanding the size of your stack. If your application does not depend on recursion, you should do this only if you encounter system error 28 during testing. If your application does depend on recursion, you might consider expanding the stack so that your application can perform deeply nested recursive computations. In addition, some object-oriented languages (for example, C++) allocate space for objects on the stack. If you are using one of these languages, you might need to expand your stack.

If you are programming in LISP or another language that depends extensively on recursion, your development system might allocate memory for local variables in the heap rather than on the stack. If so, expanding the size of the stack is not helpful. Consult your development system's documentation for details on how it allocates memory.

To increase the size of your stack, you simply reduce the size of your heap. Because the heap cannot grow above the boundary contained in the ApplLimit global variable, you can lower the value of ApplLimit to limit the heap's growth. By lowering ApplLimit , technically you are not making the stack bigger; you are just preventing collisions between it and the heap.

By default, the stack can grow to 8 KB on Macintosh computers without Color QuickDraw and to 32 KB on computers with Color QuickDraw. (The size of the stack for a faceless background process is always 8 KB, whether Color QuickDraw is present or not.) You should never decrease the size of the stack, because future versions of system software might increase the default amount of space allocated for the stack. For the same reason, you should not set the stack to a predetermined absolute size or calculate a new absolute size for the stack based on the microprocessor's type. If you must modify the size of the stack, you should increase the stack size only by some relative amount that is sufficient to meet the increased stack requirements of your application. There is no maximum size to which the stack can grow.

Listing 1-3 defines a procedure that increases the stack size by a given value. It does so by determining the current heap limit, subtracting the value of the extraBytes parameter from that value, and then setting the application limit to the difference.

Listing 3 Increasing the amount of space allocated for the stack

PROCEDURE IncreaseStackSize (extraBytes: Size);
BEGIN
    SetApplLimit(Ptr(ORD4(GetApplLimit) - extraBytes));
END;

You should call this procedure at the beginning of your application, before you call the MaxApplZone procedure (as described in the next section). If you call IncreaseStackSize after you call MaxApplZone , it has no effect, because the SetApplLimit procedure cannot change the ApplLimit global variable to a value lower than the current top of the heap.

Some compilers add to the beginning of your application some default initialization code that automatically calls MaxApplZone . You might need to specify a compiler directive that turns off such default initialization if you want to increase the size of the stack. Consult your development system's documentation for details.

Expanding the Heap

Near the beginning of your application's execution, before you allocate any memory, you should call the MaxApplZone procedure to expand the application heap immediately to the application heap limit. If you do not do this, the Memory Manager gradually expands your heap as memory needs require. This gradual expansion can result in significant heap fragmentation if you have previously moved relocatable blocks to the top of the heap (by calling MoveHHi ) and locked them (by calling HLock ). When the heap grows beyond those locked blocks, they are no longer at the top of the heap. Your heap then remains fragmented for as long as those blocks remain locked.

Another advantage to calling MaxApplZone is that doing so is likely to reduce the number of relocatable blocks that are purged by the Memory Manager. The Memory Manager expands your heap to fulfill a memory request only after it has exhausted other methods of obtaining the required amount of space, including compacting the heap and purging blocks marked as purgeable. By expanding the heap to its limit, you can prevent the Memory Manager from purging blocks that it otherwise would purge. This, together with the fact that your heap is expanded only once, can make memory allocation significantly faster.

As indicated in the previous section, you should call MaxApplZone only after you have expanded the stack, if necessary.

Allocating Master Pointer Blocks

After calling MaxApplZone , you should call the MoreMasters procedure to allocate as many new nonrelocatable blocks of master pointers as your application is likely to need during its execution. Each block of master pointers in your application heap contains 64 master pointers. The Operating System allocates one block of master pointers as your application is loaded into memory, and every relocatable block you allocate needs one master pointer to reference it.

If, when you allocate a relocatable block, there are no unused master pointers in your application heap, the Memory Manager automatically allocates a new block of master pointers. For several reasons, however, you should try to prevent the Memory Manager from calling MoreMasters for you. First, MoreMasters executes more slowly if it has to move relocatable blocks up in the heap to make room for the new nonrelocatable block of master pointers. When your application first starts running, there are no such blocks that might have to be moved. Second, the new nonrelocatable block of master pointers is likely to fragment your application heap. At any time the Memory Manager is forced to call MoreMasters for you, there are already at least 64 relocatable blocks allocated in your heap. Unless all or most of those blocks are locked high in the heap (an unlikely situation), the new nonrelocatable block of master pointers might be allocated above existing relocatable blocks. This increases heap fragmentation.

To prevent this fragmentation, you should call MoreMasters at the beginning of your application enough times to ensure that the Memory Manager never needs to call it for you. For example, if your application never allocates more than 300 relocatable blocks in its heap, then five calls to the MoreMasters should be enough. It's better to call MoreMasters too many times than too few, so if your application usually allocates about 100 relocatable blocks but sometimes might allocate 1000 in a particularly busy session, you should call MoreMasters enough times at the beginning of the program to cover the larger figure.

You can determine empirically how many times to call MoreMasters by using a low-level debugger. First, remove all the calls to MoreMasters from your code and then give your application a rigorous workout, opening and closing windows, dialog boxes, and desk accessories as much as any user would. Then, find out from your debugger how many times the system called MoreMasters . To do so, count the nonrelocatable blocks of size $100 bytes (decimal 256, or 64 4). Because of Memory Manager size corrections, you should also count any nonrelocatable blocks of size $108, $10C, or $110 bytes. (You should also check to make sure that your application doesn't allocate other nonrelocatable blocks of those sizes. If it does, subtract the number it allocates from the total.) Finally, call MoreMasters at least that many times at the beginning of your application.

Listing 1-4 illustrates a typical sequence of steps to configure your application heap and stack. The DoSetUpHeap procedure defined there increases the size of the stack by 32 KB, expands the application heap to its new limit, and allocates five additional blocks of master pointers.

Listing 4 Setting up your application heap and stack

PROCEDURE DoSetUpHeap;
CONST
    kExtraStackSpace = $8000;                           {32 KB}
    kMoreMasterCalls = 5;                               {for 320 master ptrs}
VAR
    count:      Integer;
BEGIN
    IncreaseStackSize(kExtraStackSpace);                {increase stack size}
    MaxApplZone;                                        {extend heap to limit}
    FOR count := 1 TO kMoreMasterCalls DO
        MoreMasters;                                    {64 more master ptrs}
END;

To reduce heap fragmentation, you should call DoSetUpHeap in a code segment that you never unload (possibly the main segment) rather than in a special initialization code segment. This is because MoreMasters allocates a nonrelocatable block. If you call MoreMasters from a code segment that is later purged, the new master pointer block is located above the purged space, thereby increasing fragmentation.


© 1997 Apple Computer, Inc.

Previous | Chapter Top | Chapter Contents | Next